package com.mr.security.web.commons.filter;

import com.mr.security.web.commons.config.SecurityPropertiesConfig;
import com.mr.security.web.commons.exception.ValidateCodeException;
import com.mr.security.web.commons.utils.Constants;
import com.mr.security.web.commons.validate.entity.ImageCode;
import com.mr.security.web.commons.validate.entity.ValidateCode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

/**
 * Class: ValidateCodeFilter
 * User (作者):MRui
 * TODO (描述)：手机短信验证过滤器（实际跟图形过滤器一样,只是url不同）（在登陆校验过滤器之前过滤）（OncePerRequestFilter只触发一次）
 * Date 2019-01-21 21:01
 */
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class SmsCodeValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {

    //security失败处理器
    private AuthenticationFailureHandler failureHandler;

    private Set<String> urls = new HashSet<>();

    private SecurityPropertiesConfig securityProperties;
    /** url工具类 */
    private AntPathMatcher pathMatcher = new AntPathMatcher();

    /** 该方法实现InitializingBean会在初始化后在调用 */
    @Override
    public void afterPropertiesSet() throws ServletException{
        super.afterPropertiesSet();

        if (StringUtils.isNotEmpty(securityProperties.getImageCodeUrls())){
            String[] configUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getSmsCodeUrls(),",");
            //将url
            for (String configUrl : configUrls){
                urls.add(configUrl);
            }
        }
        urls.add("authentication/mobile.do");
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        boolean action = false;
        for (String url : urls) {
            //任何一个url能匹配上返回true,则做过滤
            if(pathMatcher.match(url,httpServletRequest.getRequestURI())){
                action = true;
            }
        }
        //当是登陆表单提交并且是post请求的时候
        if(action){

        /*}
        if(StringUtils.equals("authentication/from",httpServletRequest.getRequestURI())
                        &&StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(),"post")){*/
            try {
                //校验session
                validate(new ServletWebRequest(httpServletRequest));
            } catch (ValidateCodeException e){
                //调用失败处理器返回错误信息
                failureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
                return;
            }
        }
        //调用后面的过滤器
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }

    /**
    * User (作者): MRui
    * TODO (描述)：校验规则
    * Data：2019-01-23 23:25
    */
    private void validate(ServletWebRequest request) throws ServletRequestBindingException {
        ValidateCode smsCode = (ValidateCode) request.getRequest().getSession().getAttribute(Constants.SESSION_KEY_PREFIX+"SMS");
        log.info("smsCode={}",smsCode);

        String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),"smsCode");
        log.info("codeInRequest={}",codeInRequest);

        if (StringUtils.isBlank(codeInRequest)){
            throw new ValidateCodeException("验证码的值不能为空");
        }
        if (smsCode == null){
            throw new ValidateCodeException("验证码不存在");
        }
        if (smsCode.isPeriod()){
            request.getRequest().getSession().removeAttribute(Constants.SESSION_KEY_PREFIX+"SMS");
            throw new ValidateCodeException("验证码已过期");
        }
        if (!StringUtils.equals(smsCode.getCode(),codeInRequest)){
            throw new ValidateCodeException("验证码不匹配");
        }

        request.getRequest().getSession().removeAttribute(Constants.SESSION_KEY_PREFIX+"SMS");
    }
}
